home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / libs / 3dvect39 / gus.asm < prev    next >
Encoding:
Assembly Source File  |  1994-10-30  |  46.7 KB  |  1,614 lines

  1. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2. ;
  3. ; Sound support - GUS & SB
  4. ;
  5. ; Labels begining with:
  6. ;  _sfx - generic sound commands, both cards
  7. ;  _gs  - GUS labels
  8. ;  _sb  - Sound Blaster labels
  9. ;
  10. ; Notes and Examples:
  11. ;
  12. ;  call _sfx_find              ; for both soundcards
  13. ;  jc no sound card installed
  14. ;
  15. ;  mov edx,_lomembase          ; DMA buffer        * ALL this data is ignored *
  16. ;  mov ebx, 1024               ; DMA buffer size   *  if the user has a GUS   *
  17. ;  mov ecx, 22000              ; sample rate
  18. ;  mov eax,_lomembase
  19. ;  add eax, ebx                ; samples are right after DMA buffer
  20. ;  call _sfx_init              ; call this for both soundcards (SB and GUS)
  21. ;  mul ebx,200000              ; 200000 bytes of sample memory required (0 if GUS)
  22. ;  add _lomembase,eax          ; bump up low memory because of DMA (0 if GUS)
  23. ;  add _lomembase,ebx          ; bump up low memory because of samples required (0 if GUS)
  24. ;
  25. ;  call _sfx_uninit            ; done, clear soundcard
  26. ;
  27. ; Notes: Original GUS code (now modified) from GS.ASM by Thomas Pytel, aka TRAN
  28. ;        Sound Blaster code (Gravis Emulation) by John McCarthy, aka FLYNN.
  29. ;
  30. ; Send me a postcard!
  31. ;
  32. ;        John McCarthy
  33. ;        1316 Redwood Lane
  34. ;        Pickering, Ontario.
  35. ;        Canada, Earth, Milky Way (for those out-of-towners)
  36. ;        L1X 1C5
  37. ;
  38. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  39.  
  40.          .386p
  41. code32   segment para public use32
  42.          assume cs:code32, ds:code32
  43.  
  44.          include pmode.ext
  45.          include irq.ext
  46.          include file.ext
  47.  
  48.          public _sfx_find                   ; find if sound device available
  49.          public _sfx_init                   ; intialize sound device
  50.          public _sfx_uninit                 ; unintialize sound device
  51.          public _sfx_putram                 ; put to ram
  52.          public _sfx_getram                 ; get from ram
  53.          public _sfx_shutup                 ; turn single voice off
  54.          public _sfx_relvolume              ; relative volume control
  55.          public _sfx_setvolume              ; set volume of channel
  56.          public _sfx_getfreq
  57.  
  58.          public _freqtbl                    ; precalculated frequencies for c0 to b4
  59.  
  60.          public _sfxnumvoices               ; number of voices to mix
  61.          public _sfxmem                     ; next available location in sample memory
  62.          public _sfxram                     ; amount of RAM on card
  63.          public _sfxsign                    ; sign for XOR'ing of samples (only during
  64.                                             ; initial transfer to card)
  65.          public _sfxtype                    ; card installed, 0 = none, 1 = GUS, 2 = SB
  66.  
  67.          public _vccmnd, _vccntrl, _vcsbeg, _vclbeg, _vclend, _vcfreq, _vcpan, _vcvol
  68.          public _mix_volume
  69.  
  70.          align 4
  71.  
  72. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  73. ; Generic voice handling stuff
  74. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  75.  
  76. _sfx_init   dd offset _return_null          ; jump vectors to appropriate code
  77. _sfx_uninit dd offset _return_null
  78. _sfx_putram dd offset _return_null
  79. _sfx_getram dd offset _return_null
  80. _sfx_shutup dd offset _return_null
  81. _sfx_getfreq dd offset _return_null
  82.  
  83. _sfxsign db 0                               ; signed data not, 0 = SB, 80h = GUS
  84. _sfxmem  dd 0                               ; next free location in GUS or SB virtual memory
  85. _sfxram  dd 0                               ; amount of available GUS or SB virtual memory
  86. _sfxnumvoices db 16                         ; number of voices (up to 32)
  87. _sfxmiddlec dw 8664                         ; Hz assigned to middle C
  88. _sfxtype db 0                               ; card installed, 0 = none, 1 = GUS, 2 = SB
  89.                                             ; bit 1, 1 = virtual ram or 0 = GUS ram/no ram
  90.  
  91. _vccmnd  db 32 dup(?)                       ; virtual channel command bits
  92.                                             ;  bit 0: volume change
  93.                                             ;  bit 1: balance change
  94.                                             ;  bit 2: frequency change
  95.                                             ;  bit 3: sample note-on
  96.                                             ;  bit 4: sample continues into next chunk (SB only)
  97. _vccntrl db 32 dup(?)                       ; virtual channel voice control
  98.                                             ;  bit 3: enable loop
  99.                                             ;  bit 4: bi-directional loop
  100.                                             ;  bit 6: 0=forward, 1=reverse
  101. _vcsbeg  dd 32 dup(?)                       ; virtual channel sample begin
  102. _vclbeg  dd 32 dup(?)                       ; virtual channel loop begin
  103. _vclend  dd 32 dup(?)                       ; virtual channel loop end
  104. _vcfreq  dw 32 dup(?)                       ; virtual channel frequency value
  105. _vcpan   db 32 dup(?)                       ; virtual channel pan position
  106. _vcvol   db 32 dup(?)                       ; virtual channel volume (high byte)
  107.  
  108. _mix_volume db 32 dup(15)                   ; mixing volume (each channel)
  109.  
  110. aclbeg   dd 32 dup(?)                       ; actual channel loop begin
  111. aclend   dd 32 dup(?)                       ; actual channel loop end
  112. acfreq   dw 32 dup(?)                       ; actual channel frequency value
  113. acpan    db 32 dup(?)                       ; actual channel pan position
  114. acvol    db 32 dup(?)                       ; actual channel volume (high byte)
  115. acpos    dd 32 dup(?)                       ; actual channel position           (SB only)
  116. acstep   db 32 dup(?)                       ; actual channel last step position (SB only)
  117. accntrl  db 32 dup(?)                       ; actual channel voice control      (SB only)
  118. accmnd   db 32 dup(?)                       ; actual channel command            (SB only)
  119.  
  120. _freqtbl dw 60 dup (0)
  121.  
  122. rawfreq  dw 2166,2294,2431,2573,2728,2891,3063,3245,3438,3642,3859,4088
  123.          dw 4332,4589,4862,5147,5457,5782,6126,6490,6876,7285,7718,8177
  124.          dw 8664,9179,9725,10294,10915,11565,12252,12981,13752,14571,15437,16355
  125.          dw 17328,18358,19450,20589,21831,23130,24505,25962,27505,29142,30874,32710
  126.          dw 34656,36716,38900,41179,43663,46260,49011,51925,55010,58284,61749,65421
  127.  
  128. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  129. ; Null soundcard (default)
  130. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  131.  
  132. _return_null:
  133.          xor eax,eax
  134.          xor ebx,ebx
  135.          xor ecx,ecx
  136.          xor edx,edx
  137.          xor esi,esi
  138.          xor edi,edi
  139.          xor ebp,ebp
  140.          ret
  141.  
  142. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  143. ; Macros
  144. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  145.  
  146.          vol = 1                            ; alter volume
  147.          pan = 2                            ; alter pan position
  148.          freq = 4                           ; alter frequency
  149.          play = 8                           ; start/re-start sample
  150.          cont = 16                          ; continue with SB sample (for next chunk, SB only)
  151.          shutup = 32                        ; turn channel completly off
  152.  
  153.          loop_on = 8                        ; looping enable
  154.          loop_bi = 16                       ; bi-directional loop
  155.          loop_rev = 64                      ; loop direction, 1 = backwards
  156.  
  157. gusoutb  macro index,value
  158.          mov al,&index
  159.          out dx,al
  160.          add dl,2
  161.          mov al,&value
  162.          out dx,al
  163.          sub dl,2
  164. endm
  165.  
  166. gusoutw  macro index,value
  167.          mov al,&index
  168.          out dx,al
  169.          inc edx
  170.          mov ax,&value
  171.          out dx,ax
  172.          dec edx
  173. endm
  174.  
  175. gusinb   macro reg,index
  176.          mov al,&index
  177.          out dx,al
  178.          add dl,2
  179.          in al,dx
  180.          sub dl,2
  181.          ifnb <reg>
  182.          mov reg,al
  183.          endif
  184. endm
  185.  
  186. gusinw   macro reg,index
  187.          mov al,&index
  188.          out dx,al
  189.          inc edx
  190.          in ax,dx
  191.          dec edx
  192.          ifnb <reg>
  193.          mov reg,ax
  194.          endif
  195. endm
  196.  
  197. sbout    macro data
  198.          local wait
  199. wait:    in al,dx
  200.          or al,al
  201.          js wait
  202.          mov al,data
  203.          out dx,al
  204.          endm
  205.  
  206. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  207. ; Perform Initial test for card:  Set jump vectors for card found
  208. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  209.  
  210. _sfx_find:
  211.          mov _sfxtype,0
  212.  
  213.          call _gus_find
  214.          jc fd_looksb
  215.  
  216.          mov _sfx_init ,offset _gus_init
  217.          mov _sfx_uninit,offset _gus_uninit
  218.          mov _sfx_putram,offset _gus_putram
  219.          mov _sfx_getram,offset _gus_getram
  220.          mov _sfx_shutup,offset _gus_shutup
  221.          mov _sfx_getfreq,offset _gus_getfreq
  222.          mov _sfxtype,1
  223.          mov _sfxsign,0
  224.          ret
  225.  
  226. fd_looksb:
  227.          call _sb_find
  228.          jc _ret
  229.          mov _sfx_init ,offset _sb_init
  230.          mov _sfx_uninit,offset _sb_uninit
  231.          mov _sfx_putram,offset _sb_putram
  232.          mov _sfx_getram,offset _sb_getram
  233.          mov _sfx_shutup,offset _sb_shutup
  234.          mov _sfx_getfreq,offset _sb_getfreq
  235.          mov _sfxtype,2
  236.          mov _sfxsign,0
  237.          ret
  238.  
  239. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  240. ; Set mixing volume of channel EBX
  241. ; In:
  242. ;  EBX - voice channel #
  243. ;  AL  - volume level
  244. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  245.  
  246. _sfx_setvolume:
  247.          cmp al,0
  248.          jge sv_1
  249.          mov al,0
  250. sv_1:
  251.          cmp al,15
  252.          jle sv_2
  253.          mov al,15
  254. sv_2:
  255.          mov _mix_volume[ebx],al
  256.          or _vccmnd[ebx],vol
  257.          ret
  258.  
  259. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  260. ; Change volume of channels (relative)
  261. ; In:
  262. ;   BL - channel to start at
  263. ;   CL - channel to end at
  264. ;   DL - 1 = inc, -1 = dec
  265. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  266.  
  267. _sfx_relvolume:
  268.          sub cl,bl
  269.          inc cl
  270.          movzx ebx,bl
  271.          movzx ecx,cl
  272. av_1:
  273.          mov al,_mix_volume[ebx]
  274.          add al,dl
  275.          call _sfx_setvolume
  276.          inc ebx
  277.          loop av_1
  278.  
  279.          ret
  280.  
  281. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  282. ; GUS lowlevel interface. Part II - modified from TRAN's original gs.asm
  283. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  284.  
  285.          public _gus_handler
  286.          public _gus_shutup
  287.          public _gus_init
  288.          public _gus_uninit
  289.          public _gus_putram
  290.          public _gus_getram
  291.          public _gus_find
  292.          public _gus_getfreq
  293.  
  294.          public _gusport
  295.          public _gusirq
  296.  
  297. ormgusirqvect dd ?                          ; old real mode GF1 IRQ vector
  298. rmgusirqbuf db 21 dup(?)                    ; buffer for rm GF1 IRQ callback code
  299.  
  300. gusport102 dw ?                             ; GUS port + 102h
  301. gusport103 dw ?                             ; GUS port + 103h
  302. gusport104 dw ?                             ; GUS port + 104h
  303. gusport107 dw ?                             ; GUS port + 107h
  304.  
  305. _gusport dw 220h
  306. _gusirq  db 11
  307.  
  308. whichguscontrol dd -1                       ; irq timing control number
  309.  
  310. port103val   db 43h                         ; value to set on exit from IRQ
  311. irqm0tbl     dw 0c089h,0a0e6h
  312. gusirqvaltbl db 0,0,41h,43h,0,42h,0,44h,0,0,0,45h,46h,0,0,47h
  313.  
  314. voltbl   db 004h,0a0h,0b0h,0c0h,0c8h,0d0h,0d8h,0e0h
  315.          db 0e4h,0e8h,0ech,0f0h,0f2h,0f4h,0f6h,0f8h
  316.  
  317. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  318. ; Gus IRQ - useless, never called
  319. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  320.  
  321. gus_irq:
  322.          push eax
  323.          mov al,20h
  324.          out 20h,al
  325. irqm0    dw ?                               ; out 0a0h,al | mov eax,eax
  326.          sti
  327.          cld
  328.          push ebx ecx edx esi edi ebp ds
  329.          mov ds, [cs:_seldata]
  330.  
  331.  
  332.  
  333.          pop ds ebp edi esi edx ecx ebx eax
  334.          iretd
  335.  
  336. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  337. ; Gus voice handler
  338. ; Update GUS from virtual values/commands
  339. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  340.  
  341. _gus_handler:
  342.          mov dx,gusport103
  343.          movzx ebp,_sfxnumvoices
  344.          dec ebp
  345. irql0:
  346.          xor cl,cl
  347.          xchg cl,_vccmnd[ebp]
  348.          or cl,cl
  349.          jz irql0c
  350.  
  351.          test cl,shutup
  352.          jz short irql0f9
  353.          mov edi,ebp
  354.          call _gus_shutup
  355.          jmp irql0c
  356. irql0f9:
  357.          test cl,play
  358.          jz short irql0f0
  359.          or cl,vol+pan+freq
  360. irql0f0:
  361.  
  362.          mov eax,ebp
  363.          dec edx
  364.          out dx,al
  365.          inc edx
  366.  
  367.          cmp _mix_volume[ebp],0
  368.          jne irql0g1
  369.          gusoutb 0,1
  370.          jmp irql0c
  371.  
  372. irql0g1:
  373.          test cl,freq
  374.          jz short irql0f1
  375.          mov bx,_vcfreq[ebp*2]
  376.          cmp bx,acfreq[ebp*2]
  377.          je short irql0f1
  378.          mov acfreq[ebp*2],bx
  379.          gusoutw 1,bx
  380. irql0f1:
  381.  
  382.          test cl,pan
  383.          jz short irql0f2
  384.          mov bl,_vcpan[ebp]
  385.          cmp bl,acpan[ebp]
  386.          je short irql0f2
  387.          mov acpan[ebp],bl
  388.          gusoutb 0ch,bl
  389. irql0f2:
  390.  
  391.          test cl,play
  392.          jz irql0f3
  393.          mov esi,_vclbeg[ebp*4]
  394.          cmp esi,aclbeg[ebp*4]
  395.          je short irql0f2f0
  396.          mov aclbeg[ebp*4],esi
  397.          shrd bx,si,7
  398.          shr esi,7
  399.          gusoutw 2,si
  400.          gusoutb 3,bh
  401. irql0f2f0:
  402.          mov esi,_vclend[ebp*4]
  403.          cmp esi,aclend[ebp*4]
  404.          je short irql0f2f1
  405.          mov aclend[ebp*4],esi
  406.          shrd bx,si,7
  407.          shr esi,7
  408.          gusoutw 4,si
  409.          gusoutb 5,bh
  410. irql0f2f1:
  411.          mov esi,_vcsbeg[ebp*4]
  412.          shrd bx,si,7
  413.          shr esi,7
  414.          gusoutw 0ah,si
  415.          gusoutb 0bh,bh
  416.          gusoutb 0,_vccntrl[ebp]
  417. irql0f3:
  418.  
  419.          test cl,vol
  420.          jz short irql0f4
  421.          movzx ebx,_vcvol[ebp]
  422.          mov bl,voltbl[ebx]
  423.          cmp bl,4
  424.          jbe irql0f3f4
  425.          mov bh,_mix_volume[ebp]
  426.          shl bh,3
  427.          sub bh,_mix_volume[ebp]            ; *7
  428.          add bl,bh
  429.          sub bl,105                         ; 7*15
  430. irql0f3f4:
  431.          mov bh,acvol[ebp]
  432.          mov ah,bh
  433.          cmp bh,bl
  434.          je short irql0f4
  435.          mov ch,40h
  436.          ja short irql0f3f0
  437.          xchg bl,bh
  438.          xor ch,ch
  439. irql0f3f0:
  440.          gusoutb 7,bl
  441.          gusoutb 8,bh
  442.          gusoutb 9,ah
  443.          gusoutb 0dh,ch
  444. irql0f4:
  445.  
  446.          mov dx,300h
  447.          db 7 dup(0ech)                     ; in al,dx
  448.          mov dx,gusport103
  449.  
  450.          test cl,vol
  451.          jz short irql0f5
  452.          movzx ebx,_vcvol[ebp]
  453.          mov al,voltbl[ebx]
  454.          cmp al,4
  455.          jbe irql0f5f4
  456.          mov bh,_mix_volume[ebp]
  457.          shl bh,3
  458.          sub bh,_mix_volume[ebp]            ; *7
  459.          add al,bh
  460.          sub al,105                         ; 7*15
  461. irql0f5f4:
  462.          cmp al,ah
  463.          je short irql0f5
  464.          mov acvol[ebp],al
  465.          gusoutb 9,ah
  466.          gusoutb 0dh,ch
  467. irql0f5:
  468.  
  469.          test cl,play
  470.          jz short irql0c
  471.          mov esi,_vcsbeg[ebp*4]
  472.          shrd bx,si,7
  473.          shr esi,7
  474.          gusoutw 0ah,si
  475.          gusoutb 0bh,bh
  476.          gusoutb 0,_vccntrl[ebp]
  477.  
  478. irql0c:
  479.          sub ebp,1
  480.          jnc irql0
  481.  
  482.          outb port103val
  483.          ret
  484.  
  485. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  486. ; A small delay, In: ECX - number of times to do delay
  487. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  488.  
  489. gusdelay:
  490.          push ax dx
  491.          mov dx,300h
  492. gusdelayl0:
  493.          in al,dx
  494.          in al,dx
  495.          in al,dx
  496.          in al,dx
  497.          in al,dx
  498.          in al,dx
  499.          in al,dx
  500.          in al,dx
  501.          in al,dx
  502.          loop gusdelayl0
  503.          pop dx ax
  504.          ret
  505.  
  506. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  507. ; Shove some crap into GUS ram
  508. ; In:
  509. ;   EBX - addx in GUS ram to shove into
  510. ;   ECX - amount of crap to shove
  511. ;   EDX -> actual crap to shove
  512. ; Notes:
  513. ;  All incoming data will be XOR'ed with _sfxsign  !!!
  514. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  515. _gus_putram:
  516.          push eax ebx ecx edx esi
  517.          push ecx
  518.          mov al,_sfxsign
  519.          xor al,80h
  520. gsputramlx:
  521.          xor byte ptr [edx],al
  522.          inc edx
  523.          loop gsputramlx
  524.          pop ecx
  525.          sub edx,ecx
  526.          mov esi,edx
  527.          mov dx,gusport104
  528. gsputraml0:
  529.          dec edx
  530.          mov al,44h
  531.          mov port103val,al
  532.          out dx,al
  533.          add dl,2
  534.          shld eax,ebx,16
  535.          out dx,al
  536.          sub dl,2
  537.          mov al,43h
  538.          mov port103val,al
  539.          out dx,al
  540.          inc edx
  541. gsputraml1:
  542.          mov ax,bx
  543.          out dx,ax
  544.          add dl,3
  545.          outsb
  546.          sub dl,3
  547.          inc bx
  548.          loopnz gsputraml1
  549.          jecxz short gsputramd
  550.          add ebx,10000h
  551.          jmp gsputraml0
  552. gsputramd:
  553.          pop esi edx ecx ebx eax
  554.          ret
  555.  
  556. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  557. ; Rip some crap outta GUS ram
  558. ; In:
  559. ;   EBX - addx in GUS ram to rip from
  560. ;   ECX - amount of crap to rip
  561. ;   EDX -> buffer for ripped crap
  562. ; Notes:
  563. ;  All outgoing data will be XOR'ed with _sfxsign  !!!
  564. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  565. _gus_getram:
  566.          push eax ebx ecx dx edi
  567.          push ecx
  568.          mov al,_sfxsign
  569.          xor al,80h
  570. gsgetramlx:
  571.          xor byte ptr [edx],al
  572.          inc edx
  573.          loop gsgetramlx
  574.          pop ecx
  575.          sub edx,ecx
  576.          mov edi,edx
  577.          mov dx,gusport104
  578. gsgetraml0:
  579.          dec edx
  580.          mov al,44h
  581.          mov port103val,al
  582.          out dx,al
  583.          add dl,2
  584.          shld eax,ebx,16
  585.          out dx,al
  586.          sub dl,2
  587.          mov al,43h
  588.          mov port103val,al
  589.          out dx,al
  590.          inc edx
  591. gsgetraml1:
  592.          mov ax,bx
  593.          out dx,ax
  594.          add dl,3
  595.          insb
  596.          sub dl,3
  597.          inc bx
  598.          loopnz gsgetraml1
  599.          jecxz short gsgetramd
  600.          add ebx,10000h
  601.          jmp gsgetraml0
  602. gsgetramd:
  603.          pop edi dx ecx ebx eax
  604.          ret
  605.  
  606. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  607. ; Initialize GUS
  608. ; In: none
  609. ; Out:
  610. ;   EAX = 0
  611. ;   EBX = 0 (can be used for determining if memory requuired on cpu, SB returns 1)
  612. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  613. _gus_init:
  614.          pushad
  615.          mov ax,900h
  616.          int 31h
  617.          push ax
  618.  
  619.          mov dx,_gusport                    ; set up all port vars
  620.          outb 0bh
  621.          add dx,102h
  622.          mov gusport102,dx
  623.          inc edx
  624.          mov gusport103,dx
  625.          inc edx
  626.          mov gusport104,dx
  627.          add dl,3
  628.          mov gusport107,dx
  629.  
  630.          sub dl,4                           ; initialize GUS
  631.          outb 4ch
  632.          add dl,2
  633.          outb 0
  634.          mov ecx,10h
  635.          call gusdelay
  636.          outb 1
  637.          sub dl,2
  638.          mov ecx,10h
  639.          call gusdelay
  640.          gusoutb 41h,0
  641.          gusoutb 45h,0
  642.          gusoutb 49h,0
  643.          outb 0eh
  644.          add dl,2
  645.          mov al,_sfxnumvoices
  646.          dec al
  647.          or al,0c0h
  648.          outb al
  649.          sub dl,3
  650.  
  651.          mov bl,1fh                         ; set up all voices
  652. gsinitl0:
  653.          mov al,bl
  654.          and al,7fh
  655.          out dx,al
  656.          inc edx
  657.          gusoutw 9,0
  658.          gusoutb 0,0
  659.          gusoutb 0dh,3
  660.          gusoutb 6,16
  661.          outb 0ch
  662.          add dl,2
  663.          outb 7
  664.          sub dl,3
  665.          mov ecx,1
  666.          call gusdelay
  667.          xor bl,80h
  668.          js gsinitl0
  669.          sub bl,1
  670.          jnc gsinitl0
  671.  
  672.          sub dx,0f3h                        ; damn, another undocumented port
  673.          outb 5
  674.          sub dl,0fh
  675.          outb 8
  676.          add dl,0bh
  677.          xor al,al
  678.          out dx,al
  679.          add dl,4
  680.          out dx,al
  681.          sub dl,0fh
  682.  
  683.          movzx ebx,_gusirq                  ; set IRQ channels
  684.          outb 4bh
  685.          add dl,0bh
  686.          mov al,gusirqvaltbl[ebx]
  687.          out dx,al
  688.          sub dl,0bh
  689.          outb 9
  690.          add dx,103h
  691.  
  692.          outb 43h                           ; how much RAM on the card
  693.          inc edx
  694.          outw 0ffffh
  695.          dec edx
  696.          outb 44h
  697.          add dl,2
  698.          mov cl,3
  699. gsinitl1:
  700.          outb cl
  701.          add dl,2
  702.          in al,dx
  703.          inc eax
  704.          mov ah,al
  705.          out dx,al
  706.          in al,dx
  707.          sub dl,2
  708.          cmp al,ah
  709.          jne short gsinitl1d
  710.          inc _sfxram
  711.          add cl,4
  712.          test cl,10h
  713.          jz gsinitl1
  714. gsinitl1d:
  715.          sub dl,2
  716.          shl _sfxram,18
  717.  
  718.          gusoutb 4ch,7                      ; enable GUS normal operation
  719.  
  720.          cmp bl,2                           ; set and enable GF1 IRQ (BL=IRQ num)
  721.          jne short $+4
  722.          mov bl,9
  723.          cmp bl,7
  724.          seta al
  725.          movzx eax,al
  726.          mov ax,irqm0tbl[eax*2]
  727.          mov irqm0,ax
  728.          mov edx,offset gus_irq
  729.          call _setirqvect
  730.          xor al,al
  731.          call _setirqmask
  732.          mov edi,offset rmgusirqbuf
  733.          call _rmpmirqset
  734.          mov ormgusirqvect,eax
  735.  
  736.          mov whichguscontrol,-1
  737.          call _irq_findcontrol
  738.          jc gusnogus
  739.          mov _irqcontrol[ecx*4],offset _gus_handler
  740.          mov whichguscontrol,ecx
  741. gusnogus:
  742.          mov ecx,60                         ; calculate frequency tables
  743.          mov bl,_sfxnumvoices
  744.          dec bl
  745.          and ebx,1fh
  746.          add bl,1
  747.          mov si,16
  748. gusfreqcalc:
  749.          mov ax,rawfreq[ecx*2-2]
  750.          call _gus_getfreq
  751.          mov _freqtbl[ecx*2-2],ax
  752.          loop gusfreqcalc
  753.  
  754.          pop ax
  755.          int 31h
  756.          popad
  757.          xor ebx,ebx                        ; memory flag, 0 = all samples on GUS
  758.          xor eax,eax                        ; DMA memory flag. 0 = sound blaster DMA not used
  759.          ret
  760.  
  761. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  762. ; Uninitialize GUS
  763. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  764.  
  765. _gus_uninit:
  766.          push ax bx edx
  767.          mov ax,900h
  768.          int 31h
  769.          push ax
  770.  
  771.          mov bl,_gusirq                     ; Kill GUS IRQ handler
  772.          cmp bl,2
  773.          jne short $+4
  774.          mov bl,9
  775.          mov eax,ormgusirqvect
  776.          call _rmpmirqfree
  777.          mov al,1
  778.          call _setirqmask
  779.  
  780.          mov dx,gusport103                  ; Shut down GUS
  781.          outb 4ch
  782.          add dl,2
  783.          outb 0
  784.          sub dx,105h
  785.          outb 0bh
  786.  
  787.          mov ecx,whichguscontrol
  788.          or ecx,ecx
  789.          jl gusnovoice
  790.          mov _irqcontrol[ecx*4],offset _ret
  791. gusnovoice:
  792.  
  793.          pop ax
  794.          int 31h
  795.          pop edx bx ax
  796.          ret
  797.  
  798. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  799. ; Find a GUS (environment variable)
  800. ; Out:
  801. ;   EAX,ECX,ESI,EDI - ?
  802. ;   CF=0 - found GUS
  803. ;   CF=1 - no GUS found
  804. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  805. pspultrastr db 'ULTRASND'
  806.  
  807. _gus_find:
  808.          pushad
  809.          mov esi,_pspa
  810.          movzx esi,word ptr gs:[esi+2ch]
  811.          shl esi,4
  812. gsfindl3:
  813.          mov edi,offset pspultrastr
  814.          mov ecx,8
  815.          repe cmps byte ptr gs:[esi],byte ptr es:[edi]
  816.          jne short gsfindf0
  817.          mov edi,10h
  818.          call gsfindr0
  819.          mov _gusport,cx
  820.          call gsfindr0
  821.          call gsfindr0
  822.          mov edi,10
  823.          call gsfindr0
  824.          mov _gusirq,cl
  825.          popad
  826.          clc
  827.          ret
  828. gsfindf0:
  829.          lea esi,[esi+ecx-8]
  830. gsfindl0:
  831.          inc esi
  832.          cmp byte ptr gs:[esi-1],0
  833.          jne gsfindl0
  834.          cmp byte ptr gs:[esi],0
  835.          jne gsfindl3
  836.          popad
  837.          stc
  838.          ret
  839.  
  840. gsfindr0:
  841.          movzx eax,byte ptr gs:[esi]
  842.          inc esi
  843.          sub al,'0'
  844.          jc gsfindr0
  845.          cmp al,9
  846.          ja gsfindr0
  847.          mov ecx,eax
  848. gsfindr0l0:
  849.          mov al,gs:[esi]
  850.          inc esi
  851.          sub al,'0'
  852.          jc gsfindr0d
  853.          cmp al,9
  854.          ja gsfindr0d
  855.          imul ecx,edi
  856.          add ecx,eax
  857.          jmp gsfindr0l0
  858. gsfindr0d:
  859.          ret
  860.  
  861. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  862. ; Shut voice EDI up on GUS
  863. ; In:
  864. ;   EDI - voice to kill
  865. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  866. _gus_shutup:
  867.          push edx eax ebx
  868.          mov _vccmnd[edi],0
  869.          mov dx,gusport103
  870.          mov eax,edi
  871.          dec edx                            ; 3X2
  872.          out dx,al
  873.          inc edx                            ; 3X3
  874.          gusinb bl,89h
  875.          gusoutb 6,64+48
  876.          gusoutb 7,4
  877.          gusoutb 8,bl
  878.          gusoutb 0dh,40h
  879.          pop ebx eax edx
  880.          ret
  881.  
  882. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  883. ; Convert actual frequency to GUS frequency number
  884. ; In:
  885. ;   EAX - frequency
  886. ; Out:
  887. ;   AX - GUS frequency number
  888. ;   EAX high word - ?
  889. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  890. _gus_getfreq:
  891.          push edx ebx ebp
  892.          xor ebp,ebp
  893.          mov bp,_sfxmiddlec
  894.          mul ebp
  895.          mov ebp,8664
  896.          div ebp
  897.          xor edx,edx
  898.          shl eax,10
  899.          xor ebx,ebx
  900.          mov bl,_sfxnumvoices
  901.          cmp bl,14
  902.          jae short $+4
  903.          mov bl,14
  904.          mov bx,freqact[ebx*2-14*2]
  905.          div ebx
  906.          pop ebp ebx edx
  907.          ret
  908.  
  909. freqact  dw 44100,41160,38587,36317,34300,32494,30870,29400,28063
  910.          dw 26843,25725,24696,23746,22866,22050,21289,20580,19916,19293
  911.  
  912. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  913. ; SB lowlevel interface. - Everyone knows that the SB is OUTDATED and that
  914. ; anyone whose anybody has a GUS!  These routines are for those losers...
  915. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  916.  
  917.          public _sb_find
  918.          public _sb_init
  919.          public _sb_uninit
  920.          public _sb_putram
  921.          public _sb_getram
  922.          public _sb_get_dmacount
  923.          public _sb_getfreq
  924.  
  925.          public _sbport
  926.          public _sbirq
  927.          public _sbdmabuffer
  928.          public _sbdmasize
  929.          public _sbmixspeed
  930.          public _sbvoltables
  931.          public _sbsamples
  932.          public _sbvolume
  933.  
  934. _sbport  dw 0
  935. _sbirq   db 0
  936.  
  937. _sbdmabuffer dd 0                           ; DMA buffer
  938. _sbdmasize   dd 0                           ; DMA buffer size
  939. _sbmixspeed  dw 0                           ; mixing speed, (11000,22000...)
  940. _sbvoltables dd 0                           ; pointer to volume tables
  941. _sbsamples   dd 0                           ; sample tables
  942. _sbvolume    db 50                          ; overall volume diminishing for samples (256=full) init only
  943. sbebp    dd 0                               ; temp ebp 2
  944. dmaxor   dd 0                               ; xor value to flip between dma half buffers
  945. dmachunk dd 0                               ; current dma chunk location (front/back)
  946. dmahalf  dd 0                               ; _sbdmasize /2
  947. samend   dd 0                               ; current sample end location
  948. saveebp  dd 0                               ; temp save of ebp
  949.  
  950. ormsbirqvect dd ?                           ; old real mode SB IRQ vector
  951. rmsbirqbuf db 21 dup(?)                     ; buffer for rm SB IRQ callback code
  952.  
  953. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  954. ; Find a SB (environment variable)
  955. ; Out:
  956. ;   EAX,ECX,ESI,EDI - ?
  957. ;   CF=0 - found GUS
  958. ;   CF=1 - no SB found
  959. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  960.  
  961. pspsbstr db 'BLASTER'
  962.  
  963. _sb_find:
  964.          pushad
  965.          mov esi,_pspa
  966.          movzx esi,word ptr gs:[esi+2ch]
  967.          shl esi,4
  968. sbfindl3:
  969.          mov edi,offset pspsbstr
  970.          mov ecx,7
  971.          repe cmps byte ptr gs:[esi],byte ptr es:[edi]
  972.          jne short sbfindf0
  973.  
  974.          mov ebx,esi
  975.          mov ecx,10h
  976.          mov al,"A"
  977.          mov ah,"a"
  978.          dec esi
  979. sbf_loop1:
  980.          inc esi
  981.          cmp byte ptr gs:[esi],ah
  982.          je sbf_it1
  983.          cmp byte ptr gs:[esi],al
  984.          loopne sbf_loop1
  985. sbf_it1:
  986.          mov edi,10h
  987.          call sbfindr0
  988.          mov _sbport,cx
  989.  
  990.          mov ecx,10h
  991.          mov al,"I"
  992.          mov ah,"i"
  993.          dec ebx
  994. sbf_loop2:
  995.          inc ebx
  996.          cmp byte ptr gs:[ebx],ah
  997.          je sbf_it2
  998.          cmp byte ptr gs:[ebx],al
  999.          loopne sbf_loop2
  1000. sbf_it2:
  1001.          mov esi,ebx
  1002.  
  1003.          mov edi,10
  1004.          call sbfindr0
  1005.          mov _sbirq,cl
  1006.          popad
  1007.          clc
  1008.          ret
  1009. sbfindf0:
  1010.          lea esi,[esi+ecx-7]
  1011. sbfindl0:
  1012.          inc esi
  1013.          cmp byte ptr gs:[esi-1],0
  1014.          jne sbfindl0
  1015.          cmp byte ptr gs:[esi],0
  1016.          jne sbfindl3
  1017.          popad
  1018.          stc
  1019.          ret
  1020.  
  1021. sbfindr0:
  1022.          movzx eax,byte ptr gs:[esi]
  1023.          inc esi
  1024.          sub al,'0'
  1025.          jc sbfindr0
  1026.          cmp al,9
  1027.          ja sbfindr0
  1028.          mov ecx,eax
  1029. sbfindr0l0:
  1030.          mov al,gs:[esi]
  1031.          inc esi
  1032.          sub al,'0'
  1033.          jc sbfindr0d
  1034.          cmp al,9
  1035.          ja sbfindr0d
  1036.          imul ecx,edi
  1037.          add ecx,eax
  1038.          jmp sbfindr0l0
  1039. sbfindr0d:
  1040.          ret
  1041.  
  1042. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1043. ; Shut voice EDI up on SB
  1044. ; In:
  1045. ;   EDI - voice to kill
  1046. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1047. _sb_shutup:
  1048.          mov _vccmnd[edi],0
  1049.          mov accmnd[edi],0
  1050.          ret
  1051.  
  1052. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1053. ; Sound Blaster IRQ handler
  1054. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1055.  
  1056. sb_irq:
  1057.          push eax
  1058.          mov al,20h                         ; re-enable irq
  1059.          out 20h,al
  1060. irqm00   dw ?                               ; out 0a0h,al | mov eax,eax
  1061.          sti
  1062.          cld
  1063.          push ebx ecx edx esi edi ebp ds
  1064.          mov ds, [cs:_seldata]
  1065.  
  1066.          mov dx,_sbport                     ; acknowlege sound blaster
  1067.          add dx,0eh
  1068.          in al,dx
  1069.  
  1070.          mov eax,dmaxor                     ; we are now transferring other section...
  1071.          xor dmachunk,eax                   ; flip to other dma chunk
  1072.  
  1073.          call wipe_dmachunk
  1074.          call _sb_handler
  1075.  
  1076.          pop ds ebp edi esi edx ecx ebx eax
  1077.          iretd
  1078.  
  1079. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1080. ; Wipe current dma chunk
  1081. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1082.  
  1083. wipe_dmachunk:
  1084.          push edi ecx eax
  1085.          mov ecx,dmahalf
  1086.          shr ecx,2
  1087.          mov edi,dmachunk
  1088.          mov eax,80808080h
  1089.          rep stosd
  1090.          pop eax ecx edi
  1091.          ret
  1092.  
  1093. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1094. ; Get current DMA location
  1095. ; Out:
  1096. ;  ECX = > DMA load location
  1097. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1098.  
  1099. _sb_get_dmacount:
  1100.          push eax
  1101.          xor ecx,ecx
  1102.          in al,03h                          ; get from dma controller
  1103.          mov cl,al
  1104.          in al,03h
  1105.          mov ch,al
  1106.          neg ecx
  1107.          add ecx,_sbdmasize
  1108.          add ecx,_sbdmabuffer
  1109.          dec ecx
  1110.          pop eax
  1111.          ret
  1112.  
  1113. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1114. ; Initialize SB
  1115. ;  In:
  1116. ;   EDX = > free memory for DMA buffer (must be in low memory!)
  1117. ;   EAX = > free memory for volume tables, samples (MUST BE HIGHER THAN EDX!!)
  1118. ;   EBX = > DMA buffer size (dword aligned)
  1119. ;    CX = mixing speed (11000, 22000...)
  1120. ; Out:
  1121. ;  CF - 1 error initalizing sound blaster
  1122. ;  CF - 0 ok!
  1123. ;   EAX = amount EDX was adjusted because of DMA page overlap. eg: add _lomembase,ebx
  1124. ;         this includes the original DMA size (0 if GUS)
  1125. ;   EBX = 1 (can be used for determining if memory required on cpu, GUS returns 0,eg: imul ebx,200000)
  1126. ;
  1127. ; Notes:
  1128. ;  If EAX < or = EDX, samples AND volume tables will follow DMA memory.
  1129. ;  Volume tables use 16*256 bytes of memory - make sure you remember this
  1130. ;  when allocating memory for samples.  200000 bytes of sample memory req'd
  1131. ;  means to allocate 204096 bytes of memory.
  1132. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1133.  
  1134. _sb_init:
  1135.          pushad
  1136.          mov ax,900h
  1137.          int 31h
  1138.          push ax
  1139.  
  1140.          mov [esp+28+2],ebx                 ; mov eax,ebx after final popad
  1141.          mov _sbvoltables,eax
  1142.          mov _sbdmabuffer,edx
  1143.          mov _sbdmasize,ebx
  1144.          mov _sbmixspeed,cx
  1145.          add edx,_code32a
  1146.  
  1147.          mov eax,edx                        ; make sure actual DMA address+size does not
  1148.          add eax,ebx                        ; cross a 64k page boundary
  1149.          cmp ax,dx
  1150.          ja sb_dmatalk
  1151.          dec edx
  1152.          xor dx,dx
  1153.          add edx,00010000h
  1154.          sub edx,_code32a
  1155.          mov eax,_sbdmabuffer
  1156.          sub eax,edx
  1157.          neg eax
  1158.          add eax,ebx
  1159.          mov [esp+28+2],eax
  1160.          mov _sbdmabuffer,edx
  1161.          add edx,_code32a
  1162.  
  1163. sb_dmatalk:
  1164.          mov ecx,ebx
  1165.          dec ecx
  1166.  
  1167.          mov al,05h                         ; program DMA controller
  1168.          out 0ah,al
  1169.  
  1170.          xor al,al
  1171.          out 0ch,al
  1172.  
  1173.          mov al,dl                          ; edx = location for DMA
  1174.          out 02h,al
  1175.          shr edx,8
  1176.          mov al,dl
  1177.          out 02h,al
  1178.          shr edx,8
  1179.          mov al,dl
  1180.          out 83h,al
  1181.  
  1182.          mov al,cl                          ; cx = length
  1183.          out 03h,al
  1184.          mov al,ch
  1185.          out 03h,al
  1186.          mov al,01h                         ; high length
  1187.          out 0ah,al
  1188.  
  1189.          mov al,59h
  1190.          out 0bh,al
  1191.  
  1192.          mov bl,_sbirq                      ; get protected mode IRQ going
  1193.          cmp bl,2
  1194.          jne short $+4
  1195.          mov bl,9
  1196.          cmp bl,7
  1197.          seta al
  1198.          movzx eax,al
  1199.          mov ax,irqm0tbl[eax*2]
  1200.          mov irqm00,ax
  1201.          mov edx,offset sb_irq
  1202.          call _setirqvect
  1203.          xor al,al
  1204.          call _setirqmask
  1205.          mov edi,offset rmsbirqbuf
  1206.          call _rmpmirqset
  1207.          mov ormsbirqvect,eax
  1208.  
  1209.          mov edi,_sbdmabuffer               ; clear DMA buffer
  1210.          mov al,80h
  1211.          mov ecx,_sbdmasize
  1212.          cld
  1213.          rep stosb
  1214.  
  1215. sb_resetdsp:
  1216.          mov dx,_sbport                     ; make sure SB is awake and listening
  1217.          add dx,06h
  1218.          mov al,1
  1219.          out dx,al
  1220.          in al,dx
  1221.          in al,dx
  1222.          in al,dx
  1223.          in al,dx
  1224.          in al,dx
  1225.          in al,dx
  1226.          in al,dx
  1227.          in al,dx
  1228.          xor al,al
  1229.          out dx,al
  1230.          mov cx,100
  1231. sb_waitid:
  1232.          mov dx,_sbport
  1233.          add dx,0eh
  1234.          in al,dx
  1235.          or al,al
  1236.          js sb_getid
  1237.          loop sb_waitid
  1238.  
  1239.          stc
  1240.          jmp sb_error
  1241.  
  1242. sb_getid:
  1243.          mov dx,_sbport
  1244.          add dx,0ah
  1245.          in al,dx
  1246.          cmp al,0aah
  1247.          je sb_sbok
  1248.          loop sb_waitid
  1249.  
  1250.          stc
  1251.          jmp sb_error
  1252.  
  1253. sb_sbok:
  1254.          mov dx,_sbport
  1255.          add dx,0ch
  1256.          mov ax,1000
  1257.          mul ax
  1258.          div _sbmixspeed
  1259.          neg al
  1260.          mov ah,al
  1261.          mov dx,_sbport
  1262.          add dx,0ch
  1263.          sbout 40h                         ; 40h = set digitized transfer time constant
  1264.          sbout ah
  1265.  
  1266. sb_startdma:
  1267.          mov ebx,_sbdmasize
  1268.          shr ebx,1
  1269.          dec ebx
  1270.          sbout 48h                          ; 48h = set DSP block transfer size
  1271.          sbout bl
  1272.          sbout bh
  1273.          sbout 1ch                          ; 1Ch = start auto-initialize mode
  1274.          sbout 0d1h                         ; D1h = turn sound blaster digitized sounds on
  1275.  
  1276.          mov ebx,_sbdmasize                 ; set pre-calculated DMA/2 size
  1277.          shr ebx,1
  1278.          mov dmahalf,ebx
  1279.  
  1280.          mov eax,_sbdmabuffer               ; set xor for chunk flipping
  1281.          add ebx,eax
  1282.          xor ebx,eax
  1283.          mov dmaxor,ebx
  1284.          mov dmachunk,eax
  1285.          xor dmachunk,ebx                   ; point active dma chunk to second half (while first half plays)
  1286.  
  1287.          cmp eax,_sbvoltables
  1288.          jb sb_oklocation
  1289.  
  1290.          add eax,_sbdmasize                 ; set volume table location
  1291.          mov _sbvoltables,eax
  1292. sb_oklocation:
  1293.          mov eax,_sbvoltables
  1294.          mov esi,eax
  1295.  
  1296.          add eax,16*256+256                 ; set location for virtual ram
  1297.          mov _sbsamples,eax
  1298.  
  1299.          mov ecx,16*256-1                   ; generate volume tables
  1300.          movzx ebx,_sbvolume                ; percentile volume diminishing so sample addition doesn't carry
  1301.  
  1302. sb_volloop:
  1303.          movzx eax,cl
  1304.          sub eax,80h
  1305.          movzx edi,ch
  1306.          imul edi
  1307.          shr eax,4                          ; shr eax,4 = full volume
  1308.          imul bx
  1309.          mov [esi+ecx],ah                   ; ah rather than shr eax,8
  1310.          dec ecx
  1311.          jnl sb_volloop
  1312.  
  1313.          mov ecx,256-1                      ; make master volume lookup tables
  1314. sb_mastertables:
  1315.          mov ebx,ecx
  1316.          mov eax,ecx
  1317.          and bl,0fh
  1318.          shr al,4
  1319.          imul ebx
  1320.          imul eax,17
  1321.          mov ebx,15*15
  1322.          idiv ebx
  1323.          cmp al,17
  1324.          jne sb_special
  1325.          mov al,0fh
  1326. sb_special:
  1327.          mov [esi+16*256+ecx],al
  1328.          dec ecx
  1329.          jnl sb_mastertables
  1330.  
  1331.          mov ecx,60
  1332.          xor ebx,ebx
  1333. sbpitchloop:
  1334.          movzx eax,rawfreq[ebx*2]
  1335.          call _sb_getfreq
  1336.          mov _freqtbl[ebx*2],ax
  1337.  
  1338.          inc ebx
  1339.          loop sbpitchloop
  1340.  
  1341.          pop ax
  1342.          int 31h
  1343.          popad
  1344.          mov ebx,1
  1345.          clc
  1346.          ret
  1347.  
  1348. sb_error:
  1349.          pop ax
  1350.          int 31h
  1351.          popad
  1352.          xor ebx,ebx
  1353.          xor eax,eax
  1354.          ret
  1355.  
  1356. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1357. ; Unintialize SB
  1358. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1359.  
  1360. _sb_uninit:
  1361.          pushad
  1362.          mov ax,900h
  1363.          int 31h
  1364.          push ax
  1365.          mov dx,_sbport
  1366.          add dx,0ch
  1367.          sbout 0d3h                         ; D3h = turn sound blaster digitized sounds off
  1368.          sbout 0dah                         ; DAh = exit auto-initialize mode
  1369.  
  1370.          mov bl,_sbirq                      ; restore original IRQ
  1371.          cmp bl,2
  1372.          jne short $+4
  1373.          mov bl,9
  1374.          mov eax,ormsbirqvect
  1375.          call _rmpmirqfree
  1376.          mov al,1
  1377.          call _setirqmask
  1378.          pop ax
  1379.          int 31h
  1380.          popad
  1381.          ret
  1382.  
  1383. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1384. ; Shove some crap into SB virtual ram
  1385. ; In:
  1386. ;   EBX - addx in SB virtual ram to shove into
  1387. ;   ECX - amount of crap to shove
  1388. ;   EDX -> actual crap to shove
  1389. ; Notes:
  1390. ;  All incomming data will be XOR'ed with _sfxsign  !!!
  1391. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1392.  
  1393. _sb_putram:
  1394.          pushad
  1395.          add ebx,_sbsamples
  1396. pr_loop:
  1397.          mov al,[edx]
  1398.          xor al,_sfxsign
  1399.          mov [ebx],al
  1400.          inc edx
  1401.          inc ebx
  1402.          loop pr_loop
  1403.          popad
  1404.          ret
  1405.  
  1406. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1407. ; Rip some crap outta SB virtual ram
  1408. ; In:
  1409. ;   EBX - addx in SB virtual ram to rip from
  1410. ;   ECX - amount of crap to rip
  1411. ;   EDX -> buffer for ripped crap
  1412. ; Notes:
  1413. ;  All outgoing data will be XOR'ed with _sfxsign  !!!
  1414. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1415.  
  1416. _sb_getram:
  1417.          pushad
  1418.          add ebx,_sbsamples
  1419. gr_loop:
  1420.          mov al,[ebx]
  1421.          xor al,_sfxsign
  1422.          mov [edx],al
  1423.          inc edx
  1424.          inc ebx
  1425.          loop gr_loop
  1426.          popad
  1427.          ret
  1428.  
  1429. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1430. ; Main loop - Handle sound blaster mixing/voices/looping/bidirectional/volume
  1431. ;
  1432. ; This routine simply emulates a GUS on crappy Sound Blaster.
  1433. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1434.  
  1435. _sb_handler:
  1436.          movzx ebp,_sfxnumvoices
  1437.          dec ebp
  1438.  
  1439. _sb_moreloop:
  1440.          mov sbebp,ebp
  1441.  
  1442.          test _vccmnd[ebp],shutup
  1443.          jz short sbh_0f9
  1444.          mov edi,ebp
  1445.          call _sb_shutup
  1446.          jmp sbh_next
  1447. sbh_0f9:
  1448.  
  1449.          test _vccmnd[ebp],vol
  1450.          jz sbh_more3
  1451.          mov al,_vcvol[ebp]
  1452.          mov acvol[ebp],al
  1453. sbh_more3:
  1454.  
  1455.          test _vccmnd[ebp],freq
  1456.          jz sbh_more0
  1457.          mov ax,_vcfreq[ebp]
  1458.          mov acfreq[ebp*2],ax
  1459. sbh_more0:
  1460.  
  1461.          test _vccmnd[ebp],play
  1462.          jz sbh_more1
  1463.  
  1464.          mov al,_vccntrl[ebp]
  1465.          mov accntrl[ebp],al
  1466.          mov eax,_vclbeg[ebp*4]
  1467.          add eax,_sbsamples
  1468.          mov aclbeg[ebp*4],eax
  1469.          mov edx,_vcsbeg[ebp*4]
  1470.          add edx,_sbsamples
  1471.          mov eax,_vclend[ebp*4]
  1472.          add eax,_sbsamples
  1473.          mov aclend[ebp*4],eax
  1474.          mov acpos[ebp*4],edx
  1475.          mov acstep[ebp],0
  1476.          mov bh,_vcvol[ebp]
  1477.          mov acvol[ebp],bh
  1478.          mov ax,_vcfreq[ebp]
  1479.          mov acfreq[ebp*2],ax
  1480.          mov accmnd[ebp],cont
  1481.          mov _vccmnd[ebp],0
  1482.          jmp short sbh_mixit
  1483.  
  1484. sbh_more1:
  1485.          test accmnd[ebp],cont
  1486.          jz sbh_next
  1487.  
  1488. sbh_mixit:
  1489.          mov edx,acpos[ebp*4]               ; get actual sample position
  1490.          xor ebx,ebx                        ; clear top word
  1491.          mov bl,acvol[ebp]                  ; get voice volume
  1492.          shl bl,4
  1493.          or bl,_mix_volume[ebp]             ; get channel volume
  1494.          xor eax,eax
  1495.          mov ax,acfreq[ebp*2]               ; get voice frequency scaling
  1496.          xor ecx,ecx
  1497.          test accntrl[ebp],loop_rev         ; set Z flag of looping
  1498.          mov cl,ah                          ; transfer high step temporarily
  1499.          mov ah,acstep[ebp]                 ; get step from last time through
  1500.          mov edi,aclend[ebp*4]              ; get sample end
  1501.          mov ebp,ecx                        ; set high step for sample increment
  1502.          mov samend,edi                     ; dont have an extra register, must save in memory
  1503.          mov ecx,dmahalf                    ; set loop counter
  1504.          mov edi,dmachunk                   ; find current DMA chunk (front/back half)
  1505.          mov esi,_sbvoltables               ; point to volume tables
  1506.          mov bh,byte ptr [esi+16*256+ebx]   ; mix in master volume for channel
  1507.          jnz sbh_subloop                    ; use Z flag from looping
  1508.  
  1509. sbh_addloop:
  1510.          mov bl,[edx]                       ; mixing loop, get from sample
  1511.          mov bl,[ebx+esi]                   ; volume cross referance, bh = 0 - 15, bl = byte
  1512.          add [edi],bl                       ; mix into DMA
  1513.          inc edi                            ; inc DMA location
  1514.          add ah,al                          ; increment fractional counter
  1515.          adc edx,ebp                        ; increment integer counter
  1516.          cmp samend,edx                     ; done sample?
  1517.          jbe short sbh_firstshot            ; yes, check for looping else exit
  1518.          dec ecx                            ; count, dec ecx is faster than loop
  1519.          jnz short sbh_addloop
  1520.  
  1521.          mov ebp,sbebp                      ; if cpu gets here, sample continues to next DMA chunk
  1522.          mov acpos[ebp*4],edx               ; save data from this transfer to use in next
  1523.          mov acstep[ebp],ah
  1524.          jmp sbh_next
  1525.  
  1526. sbh_firstshot:
  1527.          mov saveebp,ebp                    ; in case of looping, all registers must remain same
  1528.          mov ebp,sbebp
  1529.          test accntrl[ebp],loop_on
  1530.          jnz sbh_handlelooping
  1531.  
  1532.          mov ebp,sbebp                      ; get voice number
  1533.          mov accmnd[ebp],0                  ; voice done, clear command
  1534.          mov _vccmnd[ebp],0                 ; clear virtual command
  1535.          jmp sbh_next                       ; do next voice
  1536.  
  1537. sbh_subloop:
  1538.          mov bl,[edx]                       ; backwards mixing loop:
  1539.          mov bl,[ebx+esi]                   ; volume cross referance, bh = 0 - 15, bl = byte
  1540.          add [edi],bl                       ; mix into DMA
  1541.          inc edi                            ; inc DMA location
  1542.          add ah,al                          ; increment fractional counter
  1543.          sbb edx,ebp                        ; decrement integer counter this time
  1544.          cmp edx,samend                     ; done sample?
  1545.          jbe short sbh_firstshot            ; yes, check for looping else exit
  1546.          dec ecx                            ; count, dec ecx is faster than loop
  1547.          jnz short sbh_subloop
  1548.  
  1549.          mov ebp,sbebp                      ; if cpu gets here, sample continues to next DMA chunk
  1550.          mov acpos[ebp*4],edx               ; save data from this transfer to use in next
  1551.          mov acstep[ebp],ah
  1552.          jmp sbh_next
  1553.  
  1554. sbh_handlelooping:
  1555.          test accntrl[ebp],loop_bi
  1556.          jz short sbh_nobidir
  1557.          xor accntrl[ebp],loop_rev          ; flip direction of loop
  1558.          push eax ebx
  1559.          mov eax,aclend[ebp*4]
  1560.          mov ebx,aclbeg[ebp*4]
  1561.          mov aclend[ebp*4],ebx
  1562.          mov aclbeg[ebp*4],eax
  1563.          mov samend,ebx
  1564.          pop ebx eax
  1565. sbh_nobidir:
  1566.          mov edx,aclbeg[ebp*4]
  1567.          test accntrl[ebp],loop_rev
  1568.          jnz sbh_subtest
  1569.          mov ebp,saveebp
  1570.          dec ecx                            ; count, dec ecx is faster than loop
  1571.          jnz sbh_addloop
  1572.  
  1573. sbh_next:
  1574.          mov ebp,sbebp
  1575.          dec ebp
  1576.          jnl _sb_moreloop
  1577.  
  1578.          ret
  1579.  
  1580. sbh_subtest:
  1581.          mov ebp,saveebp                    ; backwards part of bi-directional loop
  1582.          dec ecx
  1583.          jnz sbh_subloop
  1584.          jmp short sbh_next
  1585.  
  1586. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1587. ; Convert actual frequency to SB frequency number
  1588. ; In:
  1589. ;   EAX - frequency
  1590. ; Out:
  1591. ;   AX - SB frequency scaling number
  1592. ;   EAX high word - ?
  1593. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1594.  
  1595. _sb_getfreq:
  1596.          push ebp ebx
  1597.          mov ebp,eax
  1598.          mov ax,_sfxmiddlec                 ; make pitch tables
  1599.          shl eax,16                         ; step[ebx]="middle c" * rawfreq[ebx] / mixrate / rawfreq[24*2]
  1600.          movzx ebx,_sbmixspeed
  1601.          cdq
  1602.          div ebx
  1603.          mul ebp
  1604.  
  1605.          mov ebp,8664
  1606.          div ebp
  1607.          shr eax,8
  1608.  
  1609.          pop ebx ebp
  1610.          ret
  1611.  
  1612. code32   ends
  1613.          end
  1614.